/* BSD Socket API Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include <lwip/netdb.h>

#include "tcp_client.h"


//#define TEST_SOCKET_SERVER      1


#define TCP_HOST_NAME   "scft.scicome.com"
#define PORT            9199


#ifdef TEST_SOCKET_SERVER
#define TEST_SOCKET_SERVER_IP       "192.168.3.107"
#define PORT 8000
#endif

#define SOCKET_TIME_OUT_TIME        20 //connect超时时间20秒


static const char *TAG = "tcp_client";


static int sock;

esp_err_t tcp_client_init()
{
    ESP_LOGI(TAG, "tcp client init");
    struct hostent *host = gethostbyname(TCP_HOST_NAME);    
    if(!host){        
        ESP_LOGE(TAG, "Get IP address error, %s", TCP_HOST_NAME);    
        return -1;    
    }  
    for(int i=0; host->h_addr_list[i]; i++){
        printf("IP addr %d: %s\n", i+1, 
               inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );    
    }    
#ifdef TEST_SOCKET_SERVER
    char host_ip[20];
    sprintf(host_ip, "%s", TEST_SOCKET_SERVER_IP);
#else
    char host_ip[20];
    sprintf(host_ip, "%s", inet_ntoa( *(struct in_addr*)host->h_addr_list[0] ));
#endif

    //char rx_buffer[128];
    int addr_family = 0;
    int ip_protocol = 0;

    struct sockaddr_in dest_addr;
    dest_addr.sin_addr.s_addr = inet_addr(host_ip);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(PORT);
    addr_family = AF_INET;
    ip_protocol = IPPROTO_IP;
    sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
    if (sock < 0) {
        ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
        return errno;
    }
    ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);

    int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in));
    if( err == 0) {
        set_sock_time(sock, 5, 10);
    } else {
        ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
        return errno;
    }
    ESP_LOGI(TAG, "Successfully connected");
    return ESP_OK;
}

int set_sock_time(int fd, int read_sec, int write_sec)
{
    struct timeval send_timeval;
    struct timeval recv_timeval;
    if(fd <= 0) return -1;

    send_timeval.tv_sec = write_sec<0?0:write_sec;
    send_timeval.tv_usec = 0;
    recv_timeval.tv_sec = read_sec<0?0:read_sec;;
    recv_timeval.tv_usec = 0;
    if(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &send_timeval, sizeof(send_timeval)) == -1)
    {
        return -1;
    }

    if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &recv_timeval, sizeof(recv_timeval)) == -1)
    {
        return -1;
    }
    return 0;
}

void tcp_client_close()
{
    ESP_LOGI(TAG, "close tcp socket");
    if (sock != -1) {
        shutdown(sock, 0);
        close(sock);
    }
}

esp_err_t tcp_send_data(char* data, size_t len)
{
    ESP_LOGI(TAG, "tcp_send_data, len=%d", len);
    int err = send(sock, data, len, 0);
    if (err < 0) {
        ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
        return errno;
    }
    return ESP_OK;
}

void tcp_recv_data(char* rx_buffer, size_t size, size_t* recv_len)
{
    //int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
    int len = recv(sock, rx_buffer, size, 0);
    // Error occurred during receiving
    if (len < 0) {
        *recv_len = 0;
        ESP_LOGE(TAG, "recv failed: errno %d", errno);
    }
    // Data received
    else {
        *recv_len = len;
        //rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
        ESP_LOGI(TAG, "Received %d bytes", len);
        //ESP_LOGI(TAG, "%s", rx_buffer);
    }
    ESP_LOGI(TAG, "Received %d bytes", *recv_len);
}


